package nio.netty;

import com.alibaba.fastjson.JSONObject;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import nio.netty.mapper.UserMapper;
import nio.netty.pojo.Json;
import nio.netty.pojo.User;
import nio.netty.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * description:  <br>
 * version: 1.0 <br>
 * date: 2021/4/7 14:16 <br>
 * author: 温家清
 */
public class ServerMessageHandler extends SimpleChannelInboundHandler<String>{
    /**
     * 管理全局的channel
     * GlobalEventExecutor.INSTANCE  全局事件监听器
     * 一旦将channel 加入 ChannelGroup 就不要用手动去
     * 管理channel的连接失效后移除操作，他会自己移除
     */
    private static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    /**
     * 为了实现私聊功能，这里key存储用户的唯一标识，
     * 我保存 用户的id
     * 当然 这个集合也需要自己去维护 用户的上下线 不能像 ChannelGroup那样自己去维护
     */
    private static final Map<String,Channel> all = new HashMap<>();
    private static UserMapper userMapper;
    private SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    /**
     * description: 处理从客户端接收的消息 <br>
     * version: 1.0 <br>
     * date: 2021/4/7 14:17 <br>
     * author: 温家清
     *
     * @param ctx 这是上下文
     * @param msg 这是消息，需要将之装换为Json实体类
     * @return void
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg)
            throws Exception {
        Channel channel = ctx.channel();
        SqlSession sqlSession = MybatisUtils.getSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
        Json json = JSONObject.parseObject(msg, Json.class);
        System.out.println(json);
        /**
         * 这是处理注册请求
         */
        if(json.getType().equals("register")){
            String id = json.getFrom_id();
            String pwd = json.getMessage();
           if(userMapper.selectUser(id)==null){
                userMapper.insertUser(id,pwd);
                sqlSession.commit();
//                System.out.println("正在注册");
                ctx.writeAndFlush("register:success");
           }
           else{
               System.out.println("注册失败");
               ctx.writeAndFlush("register:fail");
           }
            sqlSession.close();

            return ;


        }
        /**
         * 这是处理登录请求
         */
        else if(json.getType().equals("login")){
            String id = json.getFrom_id();
            String pwd = json.getMessage();
            System.out.println("正在查询");
            User user = userMapper.selectUser(id);

            if(user!= null && user.getPwd().equals(pwd)){
                /**
                 *   用户登录成功，通知用户,需要查看用户是否登录了
                 */
                if(all.get(user.getId())!=null){
                    ctx.writeAndFlush("login:repeat");
                    return ;
                }
                System.out.println(channel.remoteAddress().toString()+"#id:"+id+"上线了");
                ctx.writeAndFlush("login:success");
                /**
                 * 这里 ChannelGroup 底层封装会遍历给所有的channel发送消息
                 * 用户登录成功，通知其他用户
                 */
                channels.writeAndFlush(sf.format(new Date())+"\n 【用户】 "+id+" 加入聊天室 ");
                channels.add(channel);
                all.put(id, channel);
            }
            else{
                ctx.writeAndFlush("login:fail");
            }
            sqlSession.close();
            return ;
        }
        /**
         * 这是处理聊天请求
         */
        else if(json.getType().equals("chat")){
            ctx.writeAndFlush(json.getMessage());
            sqlSession.close();
            return;
        }
        /**
         * 这是处理用户私聊的信息
         */
        else if(json.getTo_id().length() != 0 ){
            String otherId = json.getTo_id();
            String id = json.getFrom_id();
            /**
             * 客户端在发送前，可以考虑在消息的#符号前面加一个@符号转义
             * 服务器在接收后，将再解码
             */
            String body = json.getMessage();

            Channel userChannel = all.get(otherId.trim());
            if(userChannel==null){
                channel.writeAndFlush(sf.format(new Date())+"\n 【用户】 "+otherId+"不存在或已退出聊天室");
                sqlSession.close();
                return;
            }
            userChannel.writeAndFlush(sf.format(new Date())+"\n 【私聊】【用户】 "+id+" 说 : "+body);
            sqlSession.close();
            return;
        }

        /**
         * 这是处理用户的群聊的消息
         */
        for (Map.Entry<String, Channel> entry : all.entrySet()) {
            String id = entry.getKey();
            Channel channel1 = entry.getValue();
            if(channel !=channel1){
                channel1.writeAndFlush(sf.format(new Date())+"\n 【全体消息】【用户】 "+json.getFrom_id()+" 说 : "+json.getMessage());
            }else{
                channel1.writeAndFlush(sf.format(new Date())+"\n 【全体消息】【自己】 "+json.getFrom_id()+" 说 : "+json.getMessage());
            }
        }
        sqlSession.close();
    }
    /**
     * channel连接状态断开后触发
     * 下线移除
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        String addr = ctx.channel().remoteAddress().toString();

        Channel channel = ctx.channel();
        for (Map.Entry<String, Channel> entry : all.entrySet()) {
            String id = entry.getKey();
            Channel channel1 = entry.getValue();
            if (channel == channel1) {
                System.out.println(sf.format(new Date())+" \n【用户】 "+addr+"#id:"+id+" 下线 ");
                all.remove(id);
                break;
            }
        }
    }
    /**
     * 连接发生异常时触发
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        //System.out.println("连接发生异常！");
        ctx.close();
    }
    /**
     * 断开连接会触发该消息
     * 同时当前channel 也会自动从ChannelGroup中被移除
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        String addr = channel.remoteAddress().toString();
        String id = "";
        /**
         * 这里 ChannelGroup 底层封装会遍历给所有的channel发送消息
         *
         */
        for (Map.Entry<String, Channel> entry : all.entrySet()) {
            id = entry.getKey();
            Channel channel1 = entry.getValue();
            if (channel == channel1) {
                break;
            }
        }
        channels.writeAndFlush(sf.format(new Date())+"\n 【用户】 "+id+" 离开了 ");
        System.out.println("当前在线人数是:"+channels.size());
        System.out.println("all："+all.size());
    }

}
